home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / tools / indent.lha / indent / indent.c < prev    next >
C/C++ Source or Header  |  1992-07-06  |  57KB  |  1,499 lines

  1. /*
  2.  * Copyright 1989 Object Design, Inc.
  3.  * Copyright (c) 1985 Sun Microsystems, Inc.
  4.  * Copyright (c) 1980 The Regents of the University of California.
  5.  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
  6.  * All rights reserved.
  7.  *
  8.  * Redistribution and use in source and binary forms are permitted
  9.  * provided that the above copyright notice and this paragraph are
  10.  * duplicated in all such forms and that any documentation,
  11.  * advertising materials, and other materials related to such
  12.  * distribution and use acknowledge that the software was developed
  13.  * by the University of California, Berkeley, the University of Illinois,
  14.  * Urbana, and Sun Microsystems, Inc.  The name of either University
  15.  * or Sun Microsystems may not be used to endorse or promote products
  16.  * derived from this software without specific prior written permission.
  17.  * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  19.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  20.  */
  21.  
  22. #ifndef lint
  23. # ifndef OS2
  24. char copyright[] =
  25. "@(#) Copyright 1989 Object Design, Inc.\n\
  26.  @(#) Copyright (c) 1985 Sun Microsystems, Inc.\n\
  27.  @(#) Copyright (c) 1980 The Regents of the University of California.\n\
  28.  @(#) Copyright (c) 1976 Board of Trustees of the University of Illinois.\n\
  29.  All rights reserved.\n";
  30.  
  31.     static char sccsid[] = "@(#)indent.c    6.0 (Berkeley) 92/06/15";
  32. # endif
  33. #endif                          /* not lint */
  34.  
  35. #include "globals.h"
  36. #include "codes.h"
  37.  
  38. #ifdef OS2                      /* or MSDOS */
  39. #include <malloc.h>
  40. #include <stdlib.h>
  41. #include <process.h>
  42. #include <string.h>
  43. #include <io.h>
  44. #define R_OK 4
  45. #define INCL_NOPM
  46. #define INCL_NOPMAPI
  47. #define INCL_BASE
  48. #define INCL_DOSFILEMGR
  49. #include <os2.h>
  50. #define MAXPATHLEN CCHMAXPATH
  51. #else                           /* not OS/2 or MSDOS */
  52. #include <sys/param.h>
  53. #include <unistd.h>
  54. #endif                          /* BSD */
  55.  
  56. #include <ctype.h>
  57.  
  58. char *in_name = "Standard Input"; /* will always point to name of input file */
  59. char *out_name = "Standard Output"; /* will always point to name of output file */
  60. char bakfile[MAXPATHLEN] = "";
  61.  
  62. #ifdef ANSIC
  63. static void bakcopy(void);
  64.  
  65. #endif
  66.  
  67. #ifdef ANSIC
  68. void main(int argc, char **argv)
  69. #else
  70. main(argc, argv)
  71.     int argc;
  72.     char **argv;
  73.  
  74. #endif
  75. {
  76.  
  77.     extern int found_err;       /* flag set in diag() on error */
  78.     int dec_ind;                /* current indentation for declarations */
  79.     int di_stack[20];           /* a stack of structure indentation levels */
  80.     int flushed_nl;             /* used when buffering up comments to remember
  81.                                    that a newline was passed over */
  82.     int force_nl;               /* when true, code must be broken */
  83.     int hd_type;                /* used to store type of stmt for if (...), for
  84.                                    (...), etc */
  85.     register int i;             /* local loop counter */
  86.     int scase;                  /* set to true when we see a case, so we will
  87.                                    know what to do with the following colon */
  88.     int sp_sw;                  /* when true, we are in the expressin of
  89.                                    if(...), while(...), etc. */
  90.     int squest;                 /* when this is positive, we have seen a ?
  91.                                    without the matching : in a <c>?<s>:<s>
  92.                                    construct */
  93.     register char *t_ptr;       /* used for copying tokens */
  94.     int type_code;              /* the type of token, returned by lexi */
  95.  
  96.     int last_else = 0;          /* true iff last keyword was an else */
  97.     int ch;                     /* answer to Y/N prompt */
  98.  
  99.     int just_saw_cc_cmnt = 0;   /* true if // comment was just emitted
  100.                                    (jrs 8jun92) */
  101.  
  102.     /*-----------------------------------------------*\
  103.     |                INITIALIZATION                   |
  104.     \*-----------------------------------------------*/
  105.  
  106.  
  107.     ps.p_stack[0] = stmt;       /* this is the parser's stack */
  108.     ps.last_nl = true;          /* this is true if the last thing scanned was a
  109.                                    newline */
  110.     ps.last_token = semicolon;
  111.     combuf = (char *) malloc(bufsize);
  112.     labbuf = (char *) malloc(bufsize);
  113.     codebuf = (char *) malloc(bufsize);
  114.     l_com = combuf + bufsize - 5;
  115.     l_lab = labbuf + bufsize - 5;
  116.     l_code = codebuf + bufsize - 5;
  117.     combuf[0] = codebuf[0] = labbuf[0] = ' '; /* set up code, label, and
  118.                                                  comment buffers */
  119.     combuf[1] = codebuf[1] = labbuf[1] = '\0';
  120.     ps.else_if = 1;             /* Default else-if special processing to on */
  121.     s_lab = e_lab = labbuf + 1;
  122.     s_code = e_code = codebuf + 1;
  123.     s_com = e_com = combuf + 1;
  124.  
  125.     buf_ptr = buf_end = in_buffer;
  126.     line_no = 1;
  127.     had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
  128.     sp_sw = force_nl = false;
  129.     ps.in_or_st = false;
  130.     ps.bl_line = true;
  131.     dec_ind = 0;
  132.     di_stack[ps.dec_nest = 0] = 0;
  133.     ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
  134.     ps.cc_comment = 0;
  135.  
  136.  
  137.     scase = ps.pcase = false;
  138.     squest = 0;
  139.     sc_end = 0;
  140.     bp_save = 0;
  141.     be_save = 0;
  142.  
  143.     output = NULL;
  144.  
  145.  
  146.  
  147.     /*--------------------------------------------------*\
  148.     |                COMMAND LINE SCAN                   |
  149.     \*--------------------------------------------------*/
  150.  
  151. #ifdef undef
  152.     max_col = 78;               /* -l78 */
  153.     lineup_to_parens = 1;       /* -lp */
  154.     ps.ljust_decl = 0;          /* -ndj */
  155.     ps.com_ind = 33;            /* -c33 */
  156.     star_comment_cont = 1;      /* -sc */
  157.     ps.ind_size = 8;            /* -i8 */
  158.     verbose = 0;
  159.     ps.decl_indent = 16;        /* -di16 */
  160.     ps.indent_parameters = 1;   /* -ip */
  161.     ps.decl_com_ind = 0;        /* if this is not set to some positive value by
  162.                                    an arg, we will set this equal to ps.com_ind */
  163.     btype_2 = 1;                /* -br */
  164.     btype_3 = 0;                /* not -brr */
  165.     cuddle_else = 1;            /* -ce */
  166.     ps.unindent_displace = 0;   /* -d0 */
  167.     ps.case_indent = 0;         /* -cli0 */
  168.     ps.case_code_indent = 1;    /* -cci1 */
  169.     format_col1_comments = 1;   /* -fc1 */
  170.     procnames_start_line = 1;   /* -psl */
  171.     proc_calls_space = 0;       /* -npcs */
  172.     parens_space = 0;           /* -nprs */
  173.     comment_delimiter_on_blankline = 1; /* -cdb */
  174.     ps.leave_comma = 1;         /* -nbc */
  175. #endif
  176.  
  177.     for (i = 1; i < argc; ++i)
  178.         if (strcmp(argv[i], "-npro") == 0)
  179.             break;
  180.     set_defaults();
  181.     if (i >= argc)
  182.         set_profile();
  183.  
  184.     for (i = 1; i < argc; ++i)
  185.     {
  186.  
  187.         /*
  188.            look thru args (if any) for changes to defaults
  189.         */
  190.         if (argv[i][0] != '-')
  191.         {                       /* no flag on parameter */
  192.             if (input == NULL)
  193.             {                   /* we must have the input file */
  194.                 in_name = argv[i];  /* remember name of input file */
  195.                 input = fopen(in_name, "r");
  196.                 if (input == NULL)
  197.                 {               /* check for open error */
  198.                     fprintf(stderr, "indent: can't open %s\n", argv[i]);
  199.                     exit(1);
  200.                 }
  201.                 continue;
  202.             }
  203.             else if (output == NULL)
  204.             {                   /* we have the output file */
  205.                 out_name = argv[i]; /* remember name of output file */
  206.                 if (strcmp(in_name, out_name) == 0)
  207.                 {               /* attempt to overwrite the file */
  208.                     fprintf(stderr, "indent: input and output files must be different\n");
  209.                     exit(1);
  210.                 }
  211.                 if (access(out_name, R_OK) == 0)
  212.                 {
  213.                     fprintf(stderr, "Reformatting input file %s to produce output file %s\n",
  214.                             in_name, out_name);
  215.                     fprintf(stderr, "Output file %s exists; overwrite it? ", out_name);
  216.                     fflush(stderr);
  217.                     if ((ch = getchar()) != 'y' && ch != 'Y')
  218.                     {
  219.                         fprintf(stderr, "indent: can't create %s\n", argv[i]);
  220.                         exit(1);
  221.                     }
  222.                 }
  223.                 output = fopen(out_name, "w");
  224.                 if (output == NULL)
  225.                 {               /* check for create error */
  226.                     fprintf(stderr, "indent: can't create %s\n", argv[i]);
  227.                     exit(1);
  228.                 }
  229.                 continue;
  230.             }
  231.             fprintf(stderr, "indent: unknown parameter: %s\n", argv[i]);
  232.             exit(1);
  233.         }
  234.         else
  235.             set_option(argv[i]);
  236.     }                           /* end of for */
  237.     if (input == NULL)
  238.     {
  239.         fprintf(stderr, "indent: usage: indent file [ outfile ] [ options ]\n");
  240.         exit(1);
  241.     }
  242.     /* set -+ mode by default for .C */
  243.     if (!cplus)                 /* don't bother if explicit */
  244.     {
  245.         char *dot;
  246.  
  247.         dot = in_name + strlen(in_name) - 2;
  248.         if ((dot > in_name) && (strcmp(dot, ".C") == 0))
  249.             set_option("-+");
  250.     }
  251.  
  252.     if (output == NULL)
  253.         if (troff)
  254.             output = stdout;
  255.         else
  256.         {
  257.             out_name = in_name;
  258.             bakcopy();
  259.         }
  260.     if (ps.com_ind <= 1)
  261.         ps.com_ind = 2;         /* don't put normal comments before column 2 */
  262.     if (troff)
  263.     {
  264.         if (bodyf.font[0] == 0)
  265.             parsefont(&bodyf, "R");
  266.         if (scomf.font[0] == 0)
  267.             parsefont(&scomf, "I");
  268.         if (blkcomf.font[0] == 0)
  269.             blkcomf = scomf, blkcomf.size += 2;
  270.         if (boxcomf.font[0] == 0)
  271.             boxcomf = blkcomf;
  272.         if (stringf.font[0] == 0)
  273.             parsefont(&stringf, "L");
  274.         if (keywordf.font[0] == 0)
  275.             parsefont(&keywordf, "B");
  276.         writefdef(&bodyf, 'B');
  277.         writefdef(&scomf, 'C');
  278.         writefdef(&blkcomf, 'L');
  279.         writefdef(&boxcomf, 'X');
  280.         writefdef(&stringf, 'S');
  281.         writefdef(&keywordf, 'K');
  282.     }
  283.     if (block_comment_max_col <= 0)
  284.         block_comment_max_col = max_col;
  285.     if (ps.decl_com_ind <= 0)   /* if not specified by user, set this */
  286.         ps.decl_com_ind = ps.ljust_decl ? (ps.com_ind <= 10 ? 2 : ps.com_ind - 8) : ps.com_ind;
  287.     if (continuation_indent == 0)
  288.         continuation_indent = ps.ind_size;
  289.  
  290.     if (tabsize <= 2)           /* If tab spacing is unreasonably small */
  291.         tabsize = 2;            /* force indent to use spaces instead. */
  292.     /* pad_output() will test this value. */
  293.  
  294.     fill_buffer();              /* get first batch of stuff into input buffer */
  295.  
  296.     parse(semicolon);
  297.     {
  298.         register char *p = buf_ptr;
  299.         register col = 1;
  300.  
  301.         while (1)
  302.         {
  303.             if (*p == ' ')
  304.                 col++;
  305.             else if (*p == '\t')
  306.                 col += (tabsize - ((col - 1) % tabsize)); /* JHT 22oct89 */
  307.             else
  308.                 break;
  309.             p++;
  310.         };
  311.         if (col > ps.ind_size)
  312.             ps.ind_level = ps.i_l_follow = col / ps.ind_size;
  313.     }
  314.     if (troff)
  315.     {
  316.         register char *p = in_name, *beg = in_name;
  317.  
  318.         while (*p)
  319.             if (*p++ == '/')
  320.                 beg = p;
  321.         fprintf(output, ".Fn \"%s\"\n", beg);
  322.     }
  323.     /*
  324.        START OF MAIN LOOP
  325.     */
  326.  
  327.     while (1)
  328.     {                           /* this is the main loop.  it will go until we
  329.                                    reach eof */
  330.         int is_procname;
  331.  
  332.         type_code = lexi();     /* lexi reads one token.  The actual characters
  333.                                    read are stored in "token". lexi returns a
  334.                                    code indicating the type of token */
  335.         is_procname = ps.procname[0];
  336.  
  337.         /*
  338.            The following code moves everything following an if (), while (),
  339.            else, etc. up to the start of the following stmt to a buffer. This
  340.            allows proper handling of both kinds of brace placement.
  341.         */
  342.  
  343.         flushed_nl = false;
  344.         while (ps.search_brace)
  345.         {                       /* if we scanned an if(), while(), etc., we
  346.                                    might need to copy stuff into a buffer we
  347.                                    must loop, copying stuff into save_com,
  348.                                    until we find the start of the stmt which
  349.                                    follows the if, or whatever */
  350.             switch (type_code)
  351.             {
  352.             case newline:
  353.                 ++line_no;
  354.                 flushed_nl = true;
  355.             case form_feed:
  356.                 break;          /* form feeds and newlines found here will be
  357.                                    ignored */
  358.  
  359.             case lbrace:       /* this is a brace that starts the compound
  360.                                    stmt */
  361.                 if (sc_end == 0)
  362.                 {               /* ignore buffering if a comment wasn't stored
  363.                                    up */
  364.                     ps.search_brace = false;
  365.                     goto check_type;
  366.                 }
  367.                 /* if (btype_2)        Bug notified by Steve Comen, 16 Mar 92 */
  368.                 {
  369.                     save_com[0] = '{';  /* we either want to put the brace
  370.                                            right after the if */
  371.                     goto sw_buffer; /* go to common code to get out of this
  372.                                        loop */
  373.                 }
  374.             case comment:      /* we have a comment, so we must copy it into
  375.                                    the buffer */
  376.                 if (!flushed_nl || sc_end != 0)
  377.                 {
  378.                     if (sc_end == 0)
  379.                     {           /* if this is the first comment, we must set up
  380.                                    the buffer */
  381.                         save_com[0] = save_com[1] = ' ';
  382.                         sc_end = &(save_com[2]);
  383.                     }
  384.                     else
  385.                     {
  386.                         *sc_end++ = '\n'; /* add newline between comments */
  387.                         *sc_end++ = ' ';
  388.                         --line_no;
  389.                     }
  390.                     *sc_end++ = '/';  /* copy in start of comment */
  391.                     *sc_end++ = '*';
  392.  
  393.                     for (;;)
  394.                     {           /* loop until we get to the end of the comment */
  395.                         *sc_end = *buf_ptr++;
  396.                         if (buf_ptr >= buf_end)
  397.                             fill_buffer();
  398.  
  399.                         if (*sc_end++ == '*' && *buf_ptr == '/')
  400.                             break;  /* we are at end of comment */
  401.  
  402.                         if (sc_end >= &(save_com[sc_size]))
  403.                         {       /* check for temp buffer overflow */
  404.                             diag(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever.");
  405.                             fflush(output);
  406.                             exit(1);
  407.                         }
  408.                     }
  409.                     *sc_end++ = '/';  /* add ending slash */
  410.                     if (++buf_ptr >= buf_end) /* get past / in buffer */
  411.                         fill_buffer();
  412.                     break;
  413.                 }
  414.             case cc_commnt:    /* we have a comment, so we must copy it into
  415.                                    the buffer */
  416.                 /* C++ comment */
  417.                 if (!flushed_nl || sc_end != 0)
  418.                 {
  419.                     if (sc_end == 0)
  420.                     {           /* if this is the first comment, we must set up
  421.                                    the buffer */
  422.                         save_com[0] = save_com[1] = ' ';
  423.                         sc_end = &(save_com[2]);
  424.                     }
  425.                     else
  426.                     {
  427.                         *sc_end++ = '\n'; /* add newline between comments */
  428.                         *sc_end++ = ' ';
  429.                         --line_no;
  430.                     }
  431.                     *sc_end++ = '/';  /* copy in start of comment */
  432.                     *sc_end++ = '/';
  433.  
  434.                     for (;;)
  435.                     {           /* loop until we get to the end of the comment */
  436.                         *sc_end++ = *buf_ptr++;
  437.                         if (buf_ptr >= buf_end)
  438.                             fill_buffer();
  439.  
  440.                         if (*buf_ptr == '\n')
  441.                             break;  /* we are at end of comment */
  442.  
  443.                         if (sc_end >= &(save_com[sc_size]))
  444.                         {       /* check for temp buffer overflow */
  445.                             diag(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever.");
  446.                             fflush(output);
  447.                             exit(1);
  448.                         }
  449.                     }
  450.                     if (++buf_ptr >= buf_end) /* eat '\n' */
  451.                         fill_buffer();
  452.                     break;
  453.                 }
  454.             default:           /* it is the start of a normal statment */
  455.                 if (flushed_nl) /* if we flushed a newline, make sure it is put
  456.                                    back */
  457.                     force_nl = true;
  458.                 if (type_code == sp_paren && *token == 'i'
  459.                     && last_else && ps.else_if
  460.                     || type_code == sp_nparen && *token == 'e'
  461.                     && e_code != s_code && e_code[-1] == '}')
  462.                     force_nl = false;
  463.  
  464.                 if (just_saw_cc_cmnt)           /* jrs 8jun92 */
  465.                 {                               /* jrs 8jun92 */
  466.                     force_nl = true;            /* jrs 8jun92 */
  467.                     just_saw_cc_cmnt = false;   /* jrs 8jun92 */
  468.                 }                               /* jrs 8jun92 */
  469.  
  470.                 if (sc_end == 0)
  471.                 {               /* ignore buffering if comment wasnt saved up */
  472.                     ps.search_brace = false;
  473.                     goto check_type;
  474.                 }
  475.                 if (force_nl)
  476.                 {               /* if we should insert a nl here, put it into
  477.                                    the buffer */
  478.                     force_nl = false;
  479.                     --line_no;  /* this will be re-increased when the nl is
  480.                                    read from the buffer */
  481.                     *sc_end++ = '\n';
  482.                     *sc_end++ = ' ';
  483.                     if (verbose && !flushed_nl) /* print error msg if the line
  484.                                                    was not already broken */
  485.                         diag(0, "Line broken");
  486.                     flushed_nl = false;
  487.                 }
  488.                 for (t_ptr = token; *t_ptr; ++t_ptr)
  489.                     *sc_end++ = *t_ptr; /* copy token into temp buffer */
  490.                 ps.procname[0] = 0;
  491.  
  492.         sw_buffer:
  493.                 ps.search_brace = false;  /* stop looking for start of stmt */
  494.                 bp_save = buf_ptr;  /* save current input buffer */
  495.                 be_save = buf_end;
  496.                 buf_ptr = save_com; /* fix so that subsequent calls to lexi
  497.                                        will take tokens out of save_com */
  498.                 *sc_end++ = ' ';/* add trailing blank, just in case */
  499.                 buf_end = sc_end;
  500.                 sc_end = 0;
  501.                 break;
  502.             }                   /* end of switch */
  503.  
  504.             just_saw_cc_cmnt = type_code == cc_commnt; /* jrs 8jun92 */
  505.  
  506.             if (type_code != 0) /* we must make this check, just in case there
  507.                                    was an unexpected EOF */
  508.                 type_code = lexi(); /* read another token */
  509.             /* if (ps.search_brace) ps.procname[0] = 0; */
  510.             if ((is_procname = ps.procname[0]) && flushed_nl
  511.                 && !procnames_start_line && ps.in_decl
  512.                 && type_code == ident)
  513.                 flushed_nl = 0;
  514.         }                       /* end of while (search_brace) */
  515.         last_else = 0;
  516. check_type:
  517.         if (type_code == 0)
  518.         {                       /* we got eof */
  519.             if (s_lab != e_lab || s_code != e_code
  520.                 || s_com != e_com)  /* must dump end of line */
  521.                 dump_line();
  522.             if (ps.tos > 1)     /* check for balanced braces */
  523.                 diag(1, "Stuff missing from end of file.");
  524.  
  525.             if (verbose)
  526.             {
  527.                 printf("There were %d output lines and %d comments\n",
  528.                        ps.out_lines, ps.out_coms);
  529.                 printf("(Lines with comments)/(Lines with code): %6.3f\n",
  530.                        (1.0 * ps.com_lines) / code_lines);
  531.             }
  532.             fflush(output);
  533.             exit(found_err);
  534.         }
  535.         if (
  536.             (type_code != comment) &&
  537.             (type_code != cc_commnt) &&
  538.             (type_code != newline) &&
  539.             (type_code != preesc) &&
  540.             (type_code != form_feed))
  541.         {
  542.             if (force_nl &&
  543.                 (type_code != semicolon) &&
  544.                 (type_code != lbrace || btype_3 || !btype_2))
  545.             {
  546.                 /* we should force a broken line here */
  547.                 if (verbose && !flushed_nl)
  548.                     diag(0, "Line broken");
  549.                 flushed_nl = false;
  550.                 dump_line();
  551.                 ps.want_blank = false;  /* dont insert blank at line start */
  552.                 force_nl = false;
  553.             }
  554.             ps.in_stmt = true;  /* turn on flag which causes an extra level of
  555.                                    indentation. this is turned off by a ; or
  556.                                    '}' */
  557.             if (s_com != e_com)
  558.             {                   /* the turkey has embedded a comment in a line.
  559.                                    fix it */
  560.                 *e_code++ = ' ';
  561.                 for (t_ptr = s_com; *t_ptr; ++t_ptr)
  562.                 {
  563.                     check_size(code);
  564.                     *e_code++ = *t_ptr;
  565.                 }
  566.                 *e_code++ = ' ';
  567.                 *e_code = '\0'; /* null terminate code sect */
  568.                 ps.want_blank = false;
  569.                 e_com = s_com;
  570.             }
  571.         }
  572.         else if (type_code != comment && type_code != cc_commnt)
  573.             /* preserve force_nl thru a comment */
  574.             force_nl = false;   /* cancel forced newline after newline, form
  575.                                    feed, etc */
  576.  
  577.  
  578.  
  579.         /*-----------------------------------------------------*\
  580.         |         do switch on type of token scanned            |
  581.         \*-----------------------------------------------------*/
  582.  
  583.         check_size(code);
  584.         switch (type_code)
  585.         {                       /* now, decide what to do with the token */
  586.  
  587.         case form_feed:        /* found a form feed in line */
  588.             ps.use_ff = true;   /* a form feed is treated much like a newline */
  589.             dump_line();
  590.             ps.want_blank = false;
  591.             break;
  592.  
  593.         case newline:
  594.             if (ps.last_token != comma || ps.p_l_follow > 0
  595.                 || !ps.leave_comma || ps.block_init || !break_comma || s_com != e_com)
  596.             {
  597.                 dump_line();
  598.                 ps.want_blank = false;
  599.             }
  600.             ++line_no;          /* keep track of input line number */
  601.             break;
  602.  
  603.         case lparen:           /* got a '(' or '[' */
  604.             ++ps.p_l_follow;    /* count parens to make Healy happy */
  605.             if (ps.want_blank && *token != '[' &&
  606.                 (ps.last_token != ident || proc_calls_space
  607.                || (ps.its_a_keyword && (!ps.sizeof_keyword || Bill_Shannon))))
  608.                 *e_code++ = ' ';
  609.             if (ps.in_decl && !ps.block_init)
  610.                 if (troff && !ps.dumped_decl_indent && !is_procname && ps.last_token == decl)
  611.                 {
  612.                     ps.dumped_decl_indent = 1;
  613.                     sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
  614.                     e_code += strlen(e_code);
  615.                 }
  616.                 else
  617.                 {
  618.                     while ((e_code - s_code) < dec_ind)
  619.                     {
  620.                         check_size(code);
  621.                         *e_code++ = ' ';
  622.                     }
  623.                     *e_code++ = token[0];
  624.                 }
  625.             else
  626.                 *e_code++ = token[0];
  627.             if (parens_space && *token != '[')
  628.                 *e_code++ = ' ';
  629.             ps.paren_indents[ps.p_l_follow - 1] = (short) (e_code - s_code);
  630.             if (sp_sw && ps.p_l_follow == 1 && extra_expression_indent
  631.                 && ps.paren_indents[0] < (short) (2 * ps.ind_size))
  632.                 ps.paren_indents[0] = (short) (2 * ps.ind_size);
  633.             ps.want_blank = false;
  634.             if (ps.in_or_st && *token == '(' && ps.tos <= 2)
  635.             {
  636.                 /*
  637.                    this is a kluge to make sure that declarations will be
  638.                    aligned right if proc decl has an explicit type on it, i.e.
  639.                    "int a(x) {..."
  640.                 */
  641.                 parse(semicolon); /* I said this was a kluge... */
  642.                 ps.in_or_st = false;  /* turn off flag for structure decl or
  643.                                          initialization */
  644.             }
  645.             if (ps.sizeof_keyword)
  646.                 ps.sizeof_mask |= 1 << ps.p_l_follow;
  647.             break;
  648.  
  649.         case rparen:           /* got a ')' or ']' */
  650.             if (ps.cast_mask & (1 << ps.p_l_follow) & ~ps.sizeof_mask)
  651.             {
  652.                 ps.last_u_d = true;
  653.                 ps.cast_mask &= (1 << ps.p_l_follow) - 1;
  654.             }
  655.             ps.sizeof_mask &= (1 << ps.p_l_follow) - 1;
  656.             if (--ps.p_l_follow < 0)
  657.             {
  658.                 ps.p_l_follow = 0;
  659.                 diag(0, "Extra %c", *token);
  660.             }
  661.             if (e_code == s_code) /* if the paren starts the line */
  662.                 ps.paren_level = ps.p_l_follow; /* then indent it */
  663.  
  664.             if (parens_space && *token != ']')
  665.                 *e_code++ = ' ';
  666.             *e_code++ = token[0];
  667.             ps.want_blank = true;
  668.  
  669.             if (sp_sw && (ps.p_l_follow == 0))
  670.             {                   /* check for end of if (...), or some such */
  671.                 sp_sw = false;
  672.                 force_nl = true;/* must force newline after if */
  673.                 ps.last_u_d = true; /* inform lexi that a following operator is
  674.                                        unary */
  675.                 ps.in_stmt = false; /* dont use stmt continuation indentation */
  676.  
  677.                 parse(hd_type); /* let parser worry about if, or whatever */
  678.             }
  679.             ps.search_brace = btype_2 && !btype_3;
  680.             /*
  681.                this should insure that constructs such as main(){...} and
  682.                int[]{...} have their braces put in the right place
  683.             */
  684.             break;
  685.  
  686.         case unary_op:         /* this could be any unary operation */
  687.             if (ps.want_blank)
  688.                 *e_code++ = ' ';
  689.  
  690.             if (troff && !ps.dumped_decl_indent && ps.in_decl && !is_procname)
  691.             {
  692.                 sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
  693.                 ps.dumped_decl_indent = 1;
  694.                 e_code += strlen(e_code);
  695.             }
  696.             else
  697.             {
  698.                 char *res = token;
  699.  
  700.                 if (ps.in_decl && !ps.block_init)
  701.                 {               /* if this is a unary op in a declaration, we
  702.                                    should indent this token */
  703.                     for (i = 0; token[i]; ++i); /* find length of token */
  704.                     while ((e_code - s_code) < (dec_ind - i))
  705.                     {
  706.                         check_size(code);
  707.                         *e_code++ = ' ';  /* pad it */
  708.                     }
  709.                 }
  710.                 if (troff && token[0] == '-' && token[1] == '>')
  711.                     res = "\\(->";
  712.                 for (t_ptr = res; *t_ptr; ++t_ptr)
  713.                 {
  714.                     check_size(code);
  715.                     *e_code++ = *t_ptr;
  716.                 }
  717.             }
  718.             ps.want_blank = false;
  719.             break;
  720.  
  721.         case binary_op:        /* any binary operation */
  722.  
  723.             if (ps.want_blank)
  724.                 *e_code++ = ' ';
  725.             {
  726.                 char *res = token;
  727.  
  728.                 if (troff)
  729.                     switch (token[0])
  730.                     {
  731.                     case '<':
  732.                         if (token[1] == '=')
  733.                             res = "\\(<=";
  734.                         break;
  735.                     case '>':
  736.                         if (token[1] == '=')
  737.                             res = "\\(>=";
  738.                         break;
  739.                     case '!':
  740.                         if (token[1] == '=')
  741.                             res = "\\(!=";
  742.                         break;
  743.                     case '|':
  744.                         if (token[1] == '|')
  745.                             res = "\\(br\\(br";
  746.                         else if (token[1] == 0)
  747.                             res = "\\(br";
  748.                         break;
  749.                     }
  750.                 for (t_ptr = res; *t_ptr; ++t_ptr)
  751.                 {
  752.                     check_size(code);
  753.                     *e_code++ = *t_ptr; /* move the operator */
  754.                 }
  755.             }
  756.             ps.want_blank = true;
  757.             break;
  758.  
  759.         case postop:           /* got a trailing ++ or -- */
  760.             *e_code++ = token[0];
  761.             *e_code++ = token[1];
  762.             ps.want_blank = true;
  763.             break;
  764.  
  765.         case question:         /* got a ? */
  766.             squest++;           /* this will be used when a later colon appears
  767.                                    so we can distinguish the <c>?<n>:<n>
  768.                                    construct */
  769.             if (ps.want_blank)
  770.                 *e_code++ = ' ';
  771.             *e_code++ = '?';
  772.             ps.want_blank = true;
  773.             break;
  774.  
  775.         case casestmt:         /* got word 'case' or 'default' */
  776.             scase = true;       /* so we can process the later colon properly */
  777.             goto copy_id;
  778.  
  779.         case privpub:          /* got public, private or protected */
  780.             strcpy(s_lab, token);
  781.             e_lab = s_lab + strlen(token);
  782.             *e_lab++ = ':';
  783.             *e_lab++ = ' ';
  784.             *e_lab = '\0';
  785.             force_nl = true;
  786.             break;
  787.  
  788.         case colon:            /* got a ':' */
  789.             if (squest > 0)
  790.             {                   /* it is part of the <c>?<n>: <n> construct */
  791.                 --squest;
  792.                 if (ps.want_blank)
  793.                     *e_code++ = ' ';
  794.                 *e_code++ = ':';
  795.                 ps.want_blank = true;
  796.                 break;
  797.             }
  798.             if (ps.in_decl)
  799.             {
  800.                 if (cplus)      /* assume public, private, or protected */
  801.                 {
  802.                     for (t_ptr = s_code; *t_ptr; ++t_ptr)
  803.                         *e_lab++ = *t_ptr;  /* turn everything so far into a
  804.                                                label */
  805.                     e_code = s_code;
  806.                     *e_lab++ = ':';
  807.                     *e_lab++ = ' ';
  808.                     *e_lab = '\0';
  809.                     force_nl = true;
  810.                     scase = false;
  811.                     ps.pcase = true;
  812.                     break;
  813.                 }
  814.                 *e_code++ = ':';
  815.                 ps.want_blank = false;
  816.                 break;
  817.             }
  818.             ps.in_stmt = false; /* seeing a label does not imply we are in a
  819.                                    stmt */
  820.             for (t_ptr = s_code; *t_ptr; ++t_ptr)
  821.                 *e_lab++ = *t_ptr;  /* turn everything so far into a label */
  822.             e_code = s_code;
  823.             *e_lab++ = ':';
  824.             *e_lab++ = ' ';
  825.             *e_lab = '\0';
  826.  
  827.             force_nl = ps.pcase = scase;  /* ps.pcase will be used by dump_line
  828.                                              to decide how to indent the label.
  829.                                              force_nl will force a case n: to
  830.                                              be on a line by itself */
  831.             scase = false;
  832.             ps.want_blank = false;
  833.             break;
  834.  
  835.         case semicolon:        /* got a ';' */
  836.             ps.in_or_st = false;/* we are not in an initialization or structure
  837.                                    declaration */
  838.             scase = false;      /* these will only need resetting in a error */
  839.             squest = 0;
  840.             if (ps.last_token == rparen)
  841.                 ps.in_parameter_declaration = 0;
  842.             ps.cast_mask = 0;
  843.             ps.sizeof_mask = 0;
  844.             ps.block_init = 0;
  845.             ps.block_init_level = 0;
  846.             ps.just_saw_decl--;
  847.  
  848.             if (ps.in_decl && s_code == e_code && !ps.block_init)
  849.                 while ((e_code - s_code) < (dec_ind - 1))
  850.                 {
  851.                     check_size(code);
  852.                     *e_code++ = ' ';
  853.                 }
  854.  
  855.             ps.in_decl = (ps.dec_nest > 0); /* if we were in a first level
  856.                                                structure declaration, we arent
  857.                                                any more */
  858.  
  859.             if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0)
  860.             {
  861.  
  862.                 /*
  863.                    This should be true iff there were unbalanced parens in the
  864.                    stmt.  It is a bit complicated, because the semicolon might
  865.                    be in a for stmt
  866.                 */
  867.                 diag(1, "Unbalanced parens");
  868.                 ps.p_l_follow = 0;
  869.                 if (sp_sw)
  870.                 {               /* this is a check for a if, while, etc. with
  871.                                    unbalanced parens */
  872.                     sp_sw = false;
  873.                     parse(hd_type); /* dont lose the if, or whatever */
  874.                 }
  875.             }
  876.             *e_code++ = ';';
  877.             ps.want_blank = true;
  878.             ps.in_stmt = (ps.p_l_follow > 0); /* we are no longer in the middle
  879.                                                  of a stmt */
  880.  
  881.             if (!sp_sw)
  882.             {                   /* if not if for (;;) */
  883.                 parse(semicolon); /* let parser know about end of stmt */
  884.                 force_nl = true;/* force newline after a end of stmt */
  885.             }
  886.             break;
  887.  
  888.         case lbrace:           /* got a '{' */
  889.             ps.in_stmt = false; /* dont indent the {} */
  890.             if (!ps.block_init)
  891.                 force_nl = true;/* force other stuff on same line as '{' onto
  892.                                    new line */
  893.             else if (ps.block_init_level <= 0)
  894.                 ps.block_init_level = 1;
  895.             else
  896.                 ps.block_init_level++;
  897.  
  898.             if (s_code != e_code && !ps.block_init)
  899.             {
  900.                 if (btype_3 || !btype_2)
  901.                 {
  902.                     dump_line();
  903.                     ps.want_blank = false;
  904.                 }
  905.                 else if (ps.in_parameter_declaration && !ps.in_or_st)
  906.                 {
  907.                     ps.i_l_follow = 0;
  908.                     dump_line();
  909.                     ps.want_blank = false;
  910.                 }
  911.             }
  912.             if (ps.in_parameter_declaration)
  913.                 prefix_blankline_requested = 0;
  914.  
  915.             if (ps.p_l_follow > 0)
  916.             {                   /* check for preceeding unbalanced parens */
  917.                 diag(1, "Unbalanced parens");
  918.                 ps.p_l_follow = 0;
  919.                 if (sp_sw)
  920.                 {               /* check for unclosed if, for, etc. */
  921.                     sp_sw = false;
  922.                     parse(hd_type);
  923.                     ps.ind_level = ps.i_l_follow;
  924.                 }
  925.             }
  926.             if (btype_3)
  927.                 ps.ind_stmt = true;
  928.             else if (s_code == e_code)
  929.                 ps.ind_stmt = false;  /* dont put extra indentation on line
  930.                                          with '{' */
  931.             if (ps.in_decl && ps.in_or_st)
  932.             {                   /* this is either a structure declaration or an
  933.                                    init */
  934.                 di_stack[ps.dec_nest++] = dec_ind;
  935.                 /* ?        dec_ind = 0; */
  936.             }
  937.             else
  938.             {
  939.                 ps.decl_on_line = false;  /* we cant be in the middle of a
  940.                                              declaration, so dont do special
  941.                                              indentation of comments */
  942.                 if (blanklines_after_declarations_at_proctop
  943.                     && ps.in_parameter_declaration)
  944.                     postfix_blankline_requested = 1;
  945.                 ps.in_parameter_declaration = 0;
  946.             }
  947.             dec_ind = 0;
  948.             parse(lbrace);      /* let parser know about this */
  949.             if (ps.want_blank)  /* put a blank before '{' if '{' is not at
  950.                                    start of line */
  951.                 *e_code++ = ' ';
  952.             ps.want_blank = false;
  953.             *e_code++ = '{';
  954.             ps.just_saw_decl = 0;
  955.             break;
  956.  
  957.         case rbrace:           /* got a '}' */
  958.             if (ps.p_stack[ps.tos] == decl && !ps.block_init) /* semicolons can be
  959.                                                                  omitted in
  960.                                                                  declarations */
  961.                 parse(semicolon);
  962.             if (ps.p_l_follow)
  963.             {                   /* check for unclosed if, for, else. */
  964.                 diag(1, "Unbalanced parens");
  965.                 ps.p_l_follow = 0;
  966.                 sp_sw = false;
  967.             }
  968.             ps.just_saw_decl = 0;
  969.             ps.block_init_level--;
  970.             if (s_code != e_code && !ps.block_init)
  971.             {                   /* '}' must be first on line */
  972.                 if (verbose)
  973.                     diag(0, "Line broken");
  974.                 dump_line();
  975.             }
  976.             *e_code++ = '}';
  977.             ps.want_blank = true;
  978.             ps.in_stmt = ps.ind_stmt = false;
  979.             if (ps.dec_nest > 0)
  980.             {                   /* we are in multi-level structure declaration */
  981.                 dec_ind = di_stack[--ps.dec_nest];
  982.                 if (ps.dec_nest == 0 && !ps.in_parameter_declaration)
  983.                     ps.just_saw_decl = 2;
  984.                 ps.in_decl = true;
  985.             }
  986.             prefix_blankline_requested = 0;
  987.             parse(rbrace);      /* let parser know about this */
  988.             ps.search_brace = cuddle_else && ps.p_stack[ps.tos] == ifhead
  989.                 && ps.il[ps.tos] >= ps.ind_level;
  990.             if (ps.tos <= 1 && blanklines_after_procs && ps.dec_nest <= 0)
  991.                 postfix_blankline_requested = 1;
  992.             if (btype_3 && ps.p_stack[ps.tos] == dohead)
  993.             {
  994.                 if (verbose)
  995.                     diag(0, "Line broken");
  996.                 dump_line();
  997.                 ps.want_blank = false;
  998.             }
  999.             break;
  1000.  
  1001.         case swstmt:           /* got keyword "switch" */
  1002.             sp_sw = true;
  1003.             hd_type = swstmt;   /* keep this for when we have seen the
  1004.                                    expression */
  1005.             goto copy_id;       /* go move the token into buffer */
  1006.  
  1007.         case sp_paren:         /* token is if, while, for */
  1008.             sp_sw = true;       /* the interesting stuff is done after the
  1009.                                    expression is scanned */
  1010.             hd_type = (*token == 'i' ? ifstmt :
  1011.                        (*token == 'w' ? whilestmt : forstmt));
  1012.  
  1013.             /*
  1014.                remember the type of header for later use by parser
  1015.             */
  1016.             goto copy_id;       /* copy the token into line */
  1017.  
  1018.         case sp_nparen:        /* got else, do */
  1019.             ps.in_stmt = false;
  1020.             if (*token == 'e')
  1021.             {
  1022.                 if (e_code != s_code && (!cuddle_else || e_code[-1] != '}'))
  1023.                 {
  1024.                     if (verbose)
  1025.                         diag(0, "Line broken");
  1026.                     dump_line();/* make sure this starts a line */
  1027.                     ps.want_blank = false;
  1028.                 }
  1029.                 force_nl = true;/* also, following stuff must go onto new line */
  1030.                 last_else = 1;
  1031.                 parse(elselit);
  1032.             }
  1033.             else
  1034.             {
  1035.                 if (e_code != s_code)
  1036.                 {               /* make sure this starts a line */
  1037.                     if (verbose)
  1038.                         diag(0, "Line broken");
  1039.                     dump_line();
  1040.                     ps.want_blank = false;
  1041.                 }
  1042.                 force_nl = true;/* also, following stuff must go onto new line */
  1043.                 last_else = 0;
  1044.                 parse(dolit);
  1045.             }
  1046.             goto copy_id;       /* move the token into line */
  1047.  
  1048.         case decl:             /* we have a declaration type (int, register,
  1049.                                    etc.) */
  1050.             parse(decl);        /* let parser worry about indentation */
  1051.             if (ps.last_token == rparen && ps.tos <= 1)
  1052.             {
  1053.                 ps.in_parameter_declaration = 1;
  1054.                 if (s_code != e_code)
  1055.                 {
  1056.                     dump_line();
  1057.                     ps.want_blank = 0;
  1058.                 }
  1059.             }
  1060.             if (ps.in_parameter_declaration && ps.indent_parameters && ps.dec_nest == 0)
  1061.             {
  1062.                 ps.ind_level = ps.i_l_follow = 1;
  1063.                 ps.ind_stmt = 0;
  1064.             }
  1065.             ps.in_or_st = true; /* this might be a structure or initialization
  1066.                                    declaration */
  1067.             ps.in_decl = ps.decl_on_line = true;
  1068.             if ( /* !ps.in_or_st && */ ps.dec_nest <= 0)
  1069.                 ps.just_saw_decl = 2;
  1070.             prefix_blankline_requested = 0;
  1071.             for (i = 0; token[i++];); /* get length of token */
  1072.  
  1073.             /*
  1074.                dec_ind = e_code - s_code + (ps.decl_indent>i ? ps.decl_indent :
  1075.                i);
  1076.             */
  1077.             dec_ind = ps.decl_indent > 0 ? ps.decl_indent : i;
  1078.             goto copy_id;
  1079.  
  1080.         case ident:            /* got an identifier or constant */
  1081.             if (ps.in_decl)
  1082.             {                   /* if we are in a declaration, we must indent
  1083.                                    identifier */
  1084.                 if (ps.want_blank)
  1085.                     *e_code++ = ' ';
  1086.                 ps.want_blank = false;
  1087.                 if (is_procname == 0 || !procnames_start_line)
  1088.                 {
  1089.                     if (!ps.block_init)
  1090.                         if (troff && !ps.dumped_decl_indent)
  1091.                         {
  1092.                             sprintf(e_code, "\n.De %dp+\200p\n", dec_ind * 7);
  1093.                             ps.dumped_decl_indent = 1;
  1094.                             e_code += strlen(e_code);
  1095.                         }
  1096.                         else
  1097.                             while ((e_code - s_code) < dec_ind)
  1098.                             {
  1099.                                 check_size(code);
  1100.                                 *e_code++ = ' ';
  1101.                             }
  1102.                 }
  1103.                 else
  1104.                 {
  1105.                     if (dec_ind && s_code != e_code)
  1106.                         dump_line();
  1107.                     dec_ind = 0;
  1108.                     ps.want_blank = false;
  1109.                 }
  1110.             }
  1111.             else if (sp_sw && ps.p_l_follow == 0)
  1112.             {
  1113.                 sp_sw = false;
  1114.                 force_nl = true;
  1115.                 ps.last_u_d = true;
  1116.                 ps.in_stmt = false;
  1117.                 parse(hd_type);
  1118.             }
  1119.     copy_id:
  1120.             if (ps.want_blank)
  1121.                 *e_code++ = ' ';
  1122.             if (troff && ps.its_a_keyword)
  1123.             {
  1124.                 e_code = chfont(&bodyf, &keywordf, e_code);
  1125.                 for (t_ptr = token; *t_ptr; ++t_ptr)
  1126.                 {
  1127.                     check_size(code);
  1128.                     *e_code++ = keywordf.allcaps && islower(*t_ptr)
  1129.                         ? (char) toupper(*t_ptr) : *t_ptr;
  1130.                 }
  1131.                 e_code = chfont(&keywordf, &bodyf, e_code);
  1132.             }
  1133.             else
  1134.                 for (t_ptr = token; *t_ptr; ++t_ptr)
  1135.                 {
  1136.                     check_size(code);
  1137.                     *e_code++ = *t_ptr;
  1138.                 }
  1139.             ps.want_blank = true;
  1140.             break;
  1141.  
  1142.         case period:           /* treat a period kind of like a binary
  1143.                                    operation */
  1144.             *e_code++ = '.';    /* move the period into line */
  1145.             ps.want_blank = false;  /* dont put a blank after a period */
  1146.             break;
  1147.  
  1148.         case comma:
  1149.             ps.want_blank = (s_code != e_code); /* only put blank after comma
  1150.                                                    if comma does not start the
  1151.                                                    line */
  1152.             if (ps.in_decl && is_procname == 0 && !ps.block_init)
  1153.                 while ((e_code - s_code) < (dec_ind - 1))
  1154.                 {
  1155.                     check_size(code);
  1156.                     *e_code++ = ' ';
  1157.                 }
  1158.  
  1159.             *e_code++ = ',';
  1160.             if (ps.p_l_follow == 0)
  1161.             {
  1162.                 if (ps.block_init_level <= 0)
  1163.                     ps.block_init = 0;
  1164.                 if (break_comma && !ps.leave_comma)
  1165.                     force_nl = true;
  1166.             }
  1167.             break;
  1168.  
  1169.         case preesc:           /* got the character '#' */
  1170.             if ((s_com != e_com) ||
  1171.                 (s_lab != e_lab) ||
  1172.                 (s_code != e_code))
  1173.                 dump_line();
  1174.             *e_lab++ = '#';     /* move whole line to 'label' buffer */
  1175.             {
  1176.                 int in_comment = 0;
  1177.                 int com_start = 0;
  1178.                 char quote = 0;
  1179.                 int com_end = 0;
  1180.  
  1181.                 while (*buf_ptr != '\n' || in_comment)
  1182.                 {
  1183.                     check_size(lab);
  1184.                     *e_lab = *buf_ptr++;
  1185.                     if (buf_ptr >= buf_end)
  1186.                         fill_buffer();
  1187.                     switch (*e_lab++)
  1188.                     {
  1189.                     case BACKSLASH:
  1190.                         if (troff)
  1191.                             *e_lab++ = BACKSLASH;
  1192.                         if (!in_comment)
  1193.                         {
  1194.                             *e_lab++ = *buf_ptr++;
  1195.                             if (buf_ptr >= buf_end)
  1196.                                 fill_buffer();
  1197.                         }
  1198.                         break;
  1199.                     case '/':
  1200.                         if (*buf_ptr == '*' && !in_comment && !quote)
  1201.                         {
  1202.                             in_comment = 1;
  1203.                             *e_lab++ = *buf_ptr++;
  1204.                             com_start = e_lab - s_lab - 2;
  1205.                         }
  1206.                         else if (*buf_ptr == '/' && !in_comment && !quote)
  1207.                         {
  1208.                             in_comment = 2;
  1209.                             *e_lab++ = *buf_ptr++;
  1210.                             com_start = e_lab - s_lab - 2;
  1211.                         }
  1212.                         break;
  1213.                     case '"':
  1214.                         if (quote == '"')
  1215.                             quote = 0;
  1216.                         break;
  1217.                     case '\'':
  1218.                         if (quote == '\'')
  1219.                             quote = 0;
  1220.                         break;
  1221.                     case '*':
  1222.                         if (*buf_ptr == '/' && in_comment == 1)
  1223.                         {
  1224.                             in_comment = 0;
  1225.                             *e_lab++ = *buf_ptr++;
  1226.                             com_end = e_lab - s_lab;
  1227.                         }
  1228.                         break;
  1229.                     case '\n':
  1230.                         if (in_comment == 2)
  1231.                         {
  1232.                             in_comment = 0;
  1233.                             --buf_ptr;  /* so while loop will exit */
  1234.                             com_end = e_lab - s_lab;
  1235.                         }
  1236.                         break;
  1237.                     }
  1238.                 }
  1239.  
  1240.                 while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
  1241.                     e_lab--;
  1242.                 if (e_lab - s_lab == com_end && bp_save == 0)
  1243.                 {               /* comment on preprocessor line */
  1244.                     if (sc_end == 0)  /* if this is the first comment, we must
  1245.                                          set up the buffer */
  1246.                         sc_end = &(save_com[0]);
  1247.                     else
  1248.                     {
  1249.                         *sc_end++ = '\n'; /* add newline between comments */
  1250.                         *sc_end++ = ' ';
  1251.                         --line_no;
  1252.                     }
  1253. #ifdef BSD                      /* gst 24 Mar 89 */
  1254.                     bcopy(s_lab + com_start, sc_end, com_end - com_start);
  1255. #else
  1256.                     memcpy(sc_end, s_lab + com_start, com_end - com_start);
  1257. #endif
  1258.                     sc_end += com_end - com_start;
  1259.                     if (sc_end >= &save_com[sc_size])
  1260.                         abort();
  1261.                     e_lab = s_lab + com_start;
  1262.                     while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
  1263.                         e_lab--;
  1264.                     bp_save = buf_ptr;  /* save current input buffer */
  1265.                     be_save = buf_end;
  1266.                     buf_ptr = save_com; /* fix so that subsequent calls to lexi
  1267.                                            will take tokens out of save_com */
  1268.                     *sc_end++ = ' ';  /* add trailing blank, just in case */
  1269.                     buf_end = sc_end;
  1270.                     sc_end = 0;
  1271.                 }
  1272.                 *e_lab = '\0';  /* null terminate line */
  1273.                 ps.pcase = false;
  1274.             }
  1275.  
  1276.             if (strncmp(s_lab, "#if", 3) == 0)
  1277.             {
  1278.                 if (blanklines_around_conditional_compilation)
  1279.                 {
  1280.                     register c;
  1281.  
  1282.                     prefix_blankline_requested++;
  1283.                     while ((c = getc(input)) == '\n');
  1284.                     ungetc(c, input);
  1285.                 }
  1286.                 if (ifdef_level < sizeof state_stack / sizeof state_stack[0])
  1287.                 {
  1288.                     match_state[ifdef_level].tos = -1;
  1289.                     state_stack[ifdef_level++] = ps;
  1290.                 }
  1291.                 else
  1292.                     diag(1, "#if stack overflow");
  1293.             }
  1294.             else if (strncmp(s_lab, "#else", 5) == 0)
  1295.                 if (ifdef_level <= 0)
  1296.                     diag(1, "Unmatched #else");
  1297.                 else
  1298.                 {
  1299.                     match_state[ifdef_level - 1] = ps;
  1300.                     ps = state_stack[ifdef_level - 1];
  1301.                 }
  1302.             else if (strncmp(s_lab, "#endif", 6) == 0)
  1303.             {
  1304.                 if (ifdef_level <= 0)
  1305.                     diag(1, "Unmatched #endif");
  1306.                 else
  1307.                 {
  1308.                     ifdef_level--;
  1309.  
  1310. #ifdef undef
  1311.                     /*
  1312.                        This match needs to be more intelligent before the
  1313.                        message is useful
  1314.                     */
  1315.                     if (match_state[ifdef_level].tos >= 0
  1316.                         && bcmp(&ps, &match_state[ifdef_level], sizeof ps))
  1317.                         diag(0, "Syntactically inconsistent #ifdef alternatives.");
  1318. #endif
  1319.                 }
  1320.                 if (blanklines_around_conditional_compilation)
  1321.                 {
  1322.                     postfix_blankline_requested++;
  1323.                     n_real_blanklines = 0;
  1324.                 }
  1325.             }
  1326.             break;              /* subsequent processing of the newline
  1327.                                    character will cause the line to be printed */
  1328.  
  1329.         case cc_commnt:        /* we have gotten a //  this is a biggie */
  1330.         case comment:          /* we have gotten a /*  this is a biggie */
  1331.  
  1332.             if (flushed_nl)
  1333.             {                   /* we should force a broken line here */
  1334.                 flushed_nl = false;
  1335.                 dump_line();
  1336.                 ps.want_blank = false;  /* dont insert blank at line start */
  1337.                 force_nl = false;
  1338.             }
  1339.             pr_comment();
  1340.             /*
  1341.                pr_comment()'s parsing sequence for a C++ comment is quite
  1342.                different from that for a standard comment.  Without the
  1343.                following test a C++ comment causes the next line to be
  1344.                formatted with an extra blank space before the code or to be
  1345.                preceded by an extra blank line.       jrs 12 mar 92
  1346.  
  1347.                (I haven't checked, but there's a good chance that fixing
  1348.                the abovementioned bug introduced another one.  For a while,
  1349.                indent would swallow the next statement after a sequence
  1350.                such as } // this type of comment.  jrs 15jun92)
  1351.             */
  1352.             if (type_code == cc_commnt) /* jrs 12 Mar 92 */
  1353.                 force_nl = ps.want_blank = false; /* jrs 12 Mar 92 */
  1354.             break;
  1355.         }                       /* end of big switch stmt */
  1356.  
  1357.         *e_code = '\0';         /* make sure code section is null terminated */
  1358.         if (type_code != comment && type_code != newline && type_code != preesc && type_code != cc_commnt)
  1359.             ps.last_token = type_code;
  1360.     }                           /* end of main while (1) loop */
  1361. }
  1362.  
  1363. /*
  1364.  * copy input file to backup file if in_name is /blah/blah/blah/file, then
  1365.  * backup file will be ".Bfile" then make the backup file the input and
  1366.  * original input file the output
  1367.  */
  1368. #ifdef ANSIC
  1369. static void bakcopy(void)
  1370. #else
  1371. bakcopy()
  1372. #endif
  1373. {
  1374. #ifdef OS2
  1375.     int fat = 0;                /* File system type = FAT? */
  1376.     char *q;
  1377.  
  1378. #endif
  1379.     int n, bakchn;
  1380.  
  1381. /*  char        buff[8 * 1024];        Ouch!  Such a big stack!
  1382.     Let's allocate a buffer from the heap instead .... jrs 12 Mar 92 */
  1383.  
  1384.     char *buff;
  1385.  
  1386. # define COPY_BUFFER_SIZE 8*1024
  1387.     register char *p;
  1388.  
  1389.     if ((buff = (char *) malloc(COPY_BUFFER_SIZE)) == NULL)
  1390.     {
  1391.         fprintf(stderr, "indent: no memory for backup file copy buffer");
  1392.         exit(1);
  1393.     }
  1394.  
  1395.     /* construct file name .Bfile */
  1396.  
  1397. #ifdef OS2                      /* or MSDOS */
  1398. # ifndef __32BIT__              /* then must be OS/2 1.x or MSDOS */
  1399. #   define DosQueryFSAttach(a,b,c,d,e) DosQFSAttach(a,b,c,(BYTE *)d,e,0L)
  1400. #   define DosQueryCurrentDisk DosQCurDisk
  1401. #   define PARAM_T USHORT
  1402.  
  1403.     DosGetMachineMode(&buff[0]);
  1404.     if (buff[0] == MODE_REAL)   /* DOS can only handle FAT */
  1405.         fat = 1;
  1406. # else
  1407. #   define PARAM_T ULONG
  1408. # endif
  1409.  
  1410.     if (!fat)
  1411.     {
  1412.         PARAM_T DriveNumber, cbData;
  1413.         ULONG DriveMap;
  1414.         struct fsqb
  1415.         {
  1416. # ifdef __32BIT__
  1417.             FSQBUFFER2 bData;
  1418. # else
  1419.             FSQBUFFER bData;
  1420. # endif
  1421.             BYTE filler[60];
  1422.         }
  1423.             fsq;
  1424.  
  1425.         cbData = sizeof fsq;
  1426.         if (isalpha(in_name[0]) && in_name[1] == ':')
  1427.             DriveNumber = toupper(in_name[0]) - '@';
  1428.         else
  1429.             DosQueryCurrentDisk(&DriveNumber, &DriveMap);
  1430.  
  1431.         if (DosQueryFSAttach(NULL, DriveNumber, FSAIL_DRVNUMBER,
  1432.                              &fsq.bData, &cbData))
  1433.             fat = 0;
  1434.         else
  1435.             fat = !strcmp(&fsq.bData.szFSDName[fsq.bData.cbName], "FAT");
  1436.     }
  1437.  
  1438.     for (p = strcpy(bakfile, in_name); *p; ++p);  /* skip to end of string */
  1439.     while (p > bakfile && *p != '/' && *p != '\\')
  1440.         p--;
  1441.     if (*p == '/' || *p == '\\')
  1442.         p++;
  1443.     if (fat && (q = strchr(p, '.')) != NULL)
  1444.         *q = '\0';
  1445.     strcat(bakfile, ".BAK");
  1446.  
  1447. #else                           /* it isn't MSDOS or OS/2 */
  1448.  
  1449.     for (p = in_name; *p; p++); /* skip to end of string */
  1450.     while (p > in_name && *p != '/')  /* find last '/' */
  1451.         p--;
  1452.     if (*p == '/')
  1453.         p++;
  1454.  
  1455.     sprintf(bakfile, "%s.BAK", p);
  1456.  
  1457. #endif
  1458.  
  1459.     /* copy in_name to backup file */
  1460.     bakchn = creat(bakfile, 0600);
  1461.     if (bakchn < 0)
  1462.     {
  1463.         fprintf(stderr, "indent: can't create backup file \"%s\"\n", bakfile);
  1464.         exit(1);
  1465.     }
  1466.     while (n = read(fileno(input), buff, COPY_BUFFER_SIZE))
  1467.         if (write(bakchn, buff, n) != n)
  1468.         {
  1469.             fprintf(stderr, "indent: error writing backup file \"%s\"\n",
  1470.                     bakfile);
  1471.             exit(1);
  1472.         }
  1473.     if (n < 0)
  1474.     {
  1475.         fprintf(stderr, "indent: error reading input file \"%s\"\n", in_name);
  1476.         exit(1);
  1477.     }
  1478.     close(bakchn);
  1479.     fclose(input);
  1480.  
  1481.     free(buff);
  1482.  
  1483.     /* re-open backup file as the input file */
  1484.     input = fopen(bakfile, "r");
  1485.     if (input == NULL)
  1486.     {
  1487.         fprintf(stderr, "indent: can't re-open backup file\n");
  1488.         exit(1);
  1489.     }
  1490.     /* now the original input file will be the output */
  1491.     output = fopen(in_name, "w");
  1492.     if (output == NULL)
  1493.     {
  1494.         fprintf(stderr, "indent: can't create %s\n", in_name);
  1495.         unlink(bakfile);
  1496.         exit(1);
  1497.     }
  1498. }
  1499.